package figure8.GUI;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.ArrayList;

import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

import figure8.Controller;
import figure8.LoopTiming;
import figure8.WAVTrack;
import figure8.WavFileException;
import figure8.GUI.EffectPanel;
import figure8.GUI.DistortionPanel;

public class EffectWindow extends JDialog {
	
	private LoopTiming timings;
	
	public enum Effect {PRE_AMP,
						DISTORTION, 
						DELAY,      
						OCTAVIA, 
						REVERSE    };
	private ArrayList<EffectPanel> effPanels;
	JPanel addPanel, buttonPanel;
	private WAVTrack track;
	private Controller controller;
	
	public EffectWindow(final Controller controller, WAVTrack track, String[] str) throws LineUnavailableException, IOException, UnsupportedAudioFileException, WavFileException{
		super();
		this.track = track;
		this.controller = controller;
		this.effPanels = new ArrayList<EffectPanel>();
		this.buildEffPanFrmStr(str);
		track.updateEffFile(effPanels);
		
	}
	
	public EffectWindow(LoopTiming timings, WAVTrack track, String[] str) throws LineUnavailableException, IOException, UnsupportedAudioFileException, WavFileException{
		super();
		this.track = track;
		this.timings = timings;
		this.effPanels = new ArrayList<EffectPanel>();
		this.buildEffPanFrmStr(str);
		track.updateEffFile(effPanels);
		
	}

	public EffectWindow(final Controller controller, 
						final WAVTrack track, 
						final WAVTrackSettingsPanel panel) {
		super();
		this.track = track;
		this.controller = controller;
		this.setTitle(track.getName() + " Effects");
		this.setLocation(panel.getX() + 8, panel.getY() + 92);
		this.setResizable(false);
		final EffectWindow effWin = this;
		this.setAlwaysOnTop(true);
		this.effPanels = new ArrayList<EffectPanel>();
		buildEffPanFrmStr(track.getEffChain());

    //Add panel
		this.addPanel = new JPanel();
		addPanel.setLayout(new BoxLayout(addPanel, BoxLayout.X_AXIS));
		
		//effect options in JComboBox
		final JComboBox options = new JComboBox(Effect.values());
		
		//add button
		JButton add = new JButton("Add");
		add.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {			
			    switch(Effect
			    	  .valueOf(options
				      .getSelectedItem()
				      .toString())) {
				case DISTORTION : effPanels.add(new DistortionPanel(effWin)); break;
				case PRE_AMP    : effPanels.add(new NoiseGatePanel(effWin)); break;
				case DELAY      : effPanels.add(new DelayPanel(effWin)); break;
				case OCTAVIA    : effPanels.add(new OctaviaPanel(effWin)); break;
				case REVERSE    : effPanels.add(new ReversePanel(effWin)); break;
			    }
			    effWin.redraw();
			}
		});
		
		//add elements to addPanel
		GridBagConstraints a1 = new GridBagConstraints();
		a1.fill = GridBagConstraints.HORIZONTAL;
		a1.fill = GridBagConstraints.VERTICAL;
		a1.gridy = 0;
		a1.gridx = 0;
		addPanel.add(options, a1);
		a1.gridx = 1;
		addPanel.add(add, a1);
		
	//Button panel
		this.buttonPanel = new JPanel();
		buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));

		//Delete All
		JButton delAll = new JButton("Delete All");
		delAll.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {				
				effPanels.clear();
				effWin.redraw();
			}
		});
		
		//Test
		JButton test = new JButton("Test");
		test.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {				
				try { 
				track.updateEffFile(effPanels);
				track.play();
				//track.setFile(track.getOrigFile());
				} catch (LineUnavailableException e1) {	e1.printStackTrace();
				} catch (IOException e1) { e1.printStackTrace();
				} catch (UnsupportedAudioFileException e1) { e1.printStackTrace(); 
				} catch (WavFileException e1) { 
					System.err.println("WavFileException: "+e1);
				}
			}
		});
		
		//Submit
		JButton submit = new JButton("Submit");
		submit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {				
                try {
					track.setEffChain(track.updateEffFile(effPanels));
				} catch (LineUnavailableException e1) {	e1.printStackTrace();
				} catch (IOException e1) { e1.printStackTrace();
				} catch (UnsupportedAudioFileException e1) { e1.printStackTrace();
				} catch (WavFileException e1) {
					System.err.println("WavFileException: "+e1);
				}
				effWin.dispose();
			}
		});
		
		//add elements to buttonPanel
		GridBagConstraints a = new GridBagConstraints();
		a.fill = GridBagConstraints.BOTH;
		a.gridy = 0;
		//a.gridwidth = 70;
		a.gridx = 0;
		buttonPanel.add(delAll, a);
		a.gridx = 1;
		buttonPanel.add(test, a);
		a.gridx = 2;
		buttonPanel.add(submit, a);
		
		
        this.redraw();
	}
	
	public void buildEffPanFrmStr(String[] str) {
		if(!str[0].equals("x")){
			for(String effStrs : str) {
				String[] setStrs = effStrs.split(":");
				boolean errorFromString = false;

				switch(Effect.valueOf(setStrs[0])) {
				case DISTORTION :
					if(setStrs.length != 3) { errorFromString = true; }
					else
						effPanels.add(
						new DistortionPanel(this, Effect.DISTORTION,
				   	 		                Double.parseDouble(setStrs[1]),
									        Double.parseDouble(setStrs[2])));
					break;
					
				case OCTAVIA    :
					if(setStrs.length != 3) { errorFromString = true; }
					else
						effPanels.add(
						new OctaviaPanel   (this, Effect.OCTAVIA,
				   	 		                Double.parseDouble(setStrs[1]),
									        Double.parseDouble(setStrs[2])));
					break;
					
				case PRE_AMP    :
					if(setStrs.length != 3) { errorFromString = true; }
					else
						effPanels.add(
						new NoiseGatePanel (this, Effect.PRE_AMP,
				   	 		                Double.parseDouble(setStrs[1]),
				   	 		                Double.parseDouble(setStrs[2])));
					break;
				case DELAY        :
					if(setStrs.length != 5) { errorFromString = true; }
					else
						effPanels.add(
						new DelayPanel   (this, Effect.DELAY,
				   	 		              Double.parseDouble(setStrs[1]),
									      Double.parseDouble(setStrs[2]),
									      Double.parseDouble(setStrs[3])));

					break;
				case REVERSE        :
					if(setStrs.length != 3) { errorFromString = true; }
					else
						effPanels.add(
						new ReversePanel   (this, Effect.REVERSE,
				   	 		                Double.parseDouble(setStrs[1])));
					break;
				default   :
					errorFromString = true;
				}
				if(errorFromString)
					System.err.println("Error: problem constructing effect panel from String" );
			}
		}
	}
	
	public void effPanelDeletion(EffectPanel panelToDel){
		effPanels.remove(panelToDel);
		redraw();
	}
	
	public void redraw() {
		this.getContentPane().removeAll();
		if(effPanels.isEmpty())
			this.getContentPane().setLayout(new GridBagLayout());
		else {
			this.getContentPane().setLayout(new GridBagLayout());
			GridBagConstraints c = new GridBagConstraints();
			//natural height, maximum width
			c.fill = GridBagConstraints.HORIZONTAL;

			int i = 0;
			for(EffectPanel eff : effPanels){
				c.fill = GridBagConstraints.HORIZONTAL;
				c.gridx = 0;
				c.gridy = i;
				this.getContentPane().add(eff, c);
				i++;
			}
		}
		
		GridBagConstraints a = new GridBagConstraints();
		a.fill = GridBagConstraints.BOTH;
		a.gridy = effPanels.size();
		a.insets = new Insets(5,15,0,15);
		this.getContentPane().add(addPanel, a);
		a.gridy = effPanels.size() + 1;
		a.insets = new Insets(5,15,5,15);
		this.getContentPane().add(buttonPanel, a);
		this.pack();
		this.setVisible(true);
	}
	
	public LoopTiming getLoopTiming() {
		if (timings != null) return timings;
		else return controller.getProject().getTiming();
	}

}